﻿using System.Net;
using System.Numerics;

namespace xrwang.DDNS
{
    /// <summary>
    /// IP地址范围
    /// </summary>
    public class IPAddressRange
    {
        /// <summary>
        /// 最小IP地址
        /// </summary>
        public IPAddress Min { get; private set; }
        /// <summary>
        /// 最小值
        /// </summary>
        private BigInteger minValue;
        /// <summary>
        /// 最大IP地址
        /// </summary>
        public IPAddress Max { get; private set; }
        /// <summary>
        /// 最大值
        /// </summary>
        private BigInteger maxValue;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="min">最小IP地址</param>
        /// <param name="max">最大IP地址</param>
        public IPAddressRange(IPAddress min, IPAddress max)
        {
            BigInteger _minValue = min.GetIPAddressValue();
            BigInteger _maxValue = max.GetIPAddressValue();
            if (minValue <= maxValue)
            {
                Min = min;
                Max = max;
                minValue = _minValue;
                maxValue = _maxValue;
            }
            else
            {
                Min = max;
                Max = min;
                minValue = _maxValue;
                maxValue = _minValue;
            }
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="min">最小IP地址</param>
        /// <param name="max">最大IP地址</param>
        public IPAddressRange(string min, string max)
            : this(IPAddress.Parse(min), IPAddress.Parse(max)) { }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="min">最小IP地址</param>
        /// <param name="max">最大IP地址</param>
        public IPAddressRange(long min, long max)
            : this(new IPAddress(min), new IPAddress(max)) { }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="min">最小IP地址</param>
        /// <param name="max">最大IP地址</param>
        public IPAddressRange(byte[] min, byte[] max)
        : this(new IPAddress(min), new IPAddress(max)) { }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="min">最小IP地址</param>
        /// <param name="max">最大IP地址</param>
        public IPAddressRange(ReadOnlySpan<byte> min, ReadOnlySpan<byte> max)
            : this(new IPAddress(min), new IPAddress(max)) { }

        /// <summary>
        /// 返回字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return string.Format("IP地址范围，最小IP地址：{0}，最大IP地址：{1}。", Min, Max);
        }

        /// <summary>
        /// 判断IP地址是否在范围之内
        /// </summary>
        /// <param name="ip">IP地址</param>
        /// <returns>返回IP地址是否在范围之内</returns>
        public bool IsInRange(IPAddress ip)
        {
            BigInteger ipValue = ip.GetIPAddressValue();
            return IsInRange(ipValue);
        }

        /// <summary>
        /// 判断IP地址是否在范围之内
        /// </summary>
        /// <param name="ipValue">IP地址的值</param>
        /// <returns>返回IP地址是否在范围之内</returns>
        internal bool IsInRange(BigInteger ipValue)
        {
            return minValue <= ipValue && maxValue >= ipValue;
        }

        /// <summary>
        /// 判断IP地址是否在范围之内
        /// </summary>
        /// <param name="min">最小IP地址</param>
        /// <param name="max">最大IP地址</param>
        /// <param name="ip">IP地址</param>
        /// <returns>返回IP地址是否在范围之内</returns>
        public static bool IsInRange(IPAddress min, IPAddress max, IPAddress ip)
        {
            return new IPAddressRange(min, max).IsInRange(ip);
        }

        /// <summary>
        /// 判断IP地址是否在范围之内
        /// </summary>
        /// <param name="min">最小IP地址</param>
        /// <param name="max">最大IP地址</param>
        /// <param name="ipValue">IP地址值</param>
        /// <returns>返回IP地址是否在范围之内</returns>
        internal static bool IsInRange(IPAddress min, IPAddress max, BigInteger ipValue)
        {
            return new IPAddressRange(min, max).IsInRange(ipValue);
        }
    }
}